package com.nervenets.web.controller.bank;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.icbc.api.IcbcApiException;
import com.icbc.api.response.*;
import com.icbc.util.SecretUtils;
import com.nervenets.utils.JodaUtils;
import com.nervenets.utils.NumberUtil;
import com.nervenets.utils.StringUtils;
import com.nervenets.web.controller.BaseController;
import com.nervenets.web.controller.IdTokenParams;
import com.nervenets.web.controller.TokenParams;
import com.nervenets.web.entity.KeyValue;
import com.nervenets.web.entity.MessageCode;
import com.nervenets.web.hibernate.dao.*;
import com.nervenets.web.hibernate.domain.*;
import com.nervenets.web.service.IcbcService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.IOUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.nervenets.web.service.IcbcService.MY_SM2_PRIVATE_KEY;

@Api(value = "诚意金接口v1", description = "诚意金相关接口")
@RestController
@RequestMapping("/api/v1/bank")
public class BankController extends BaseController {
    @Resource
    private IcbcService icbcService;
    @Resource
    private AccountOpenDao accountOpenDao;
    @Resource
    private AccountOpenBindingDao accountOpenBindingDao;
    @Resource
    private UserDao userDao;
    @Resource
    private AccountHoldDao accountHoldDao;
    @Resource
    private IcbcDataDao icbcDataDao;

    @ApiOperation("开户信息")
    @PostMapping("/account")
    public String account(@RequestBody TokenParams params) {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        final User user = userDao.findById(params.resolveUserId()).orElse(null);
        if (null == user) return errorMessage(MessageCode.code_777);
        return successMessage(accountOpenDao.findTop1ByUser(user));
    }

    @ApiOperation("开户")
    @PostMapping("/accountOpen")
    public String accountOpen(@RequestBody AccountOpenParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null != accountOpen && !StringUtils.isEmpty(accountOpen.getCard2()))
                return errorMessage(MessageCode.code_444, "您已开户成功，不需重复开户");

            if (null == accountOpen) accountOpen = new AccountOpen();
            accountOpen.setUser(user);
            accountOpen.setTrueName(params.getTrueName());
            accountOpen.setIdFrontImage(params.getIdFrontImage());
            accountOpen.setIdBackImage(params.getIdBackImage());
            accountOpen.setIdCard(params.getIdCard());
            accountOpen.setIdCardInvalidDate(params.getIdCardInvalidDate());
            accountOpen.setIdCardSignDate(params.getIdCardSignDate());
            accountOpenDao.save(accountOpen);

            AccountOpenBinding binding = accountOpenBindingDao.findByOpenAndBindCard(accountOpen, params.getBindCard());
            if (null == binding) binding = new AccountOpenBinding();
            binding.setOpen(accountOpen);
            binding.setMobile(params.getMobile());
            binding.setBindCard(params.getBindCard());
            binding.setType(0);
            binding.setCorpSerNo(StringUtils.getRandomString(16));
            accountOpenBindingDao.save(binding);

            if (StringUtils.isEmpty(user.getMobile())) {
                user.setMobile(params.getMobile());
                userDao.save(user);
            }
            try {
                SettlementAccountOpenRealtimeimgUploadResponseV1 realtimeUploadResponse = icbcService.settlementAccountOpenRealtimeImageUpload(accountOpen, binding);
                if (realtimeUploadResponse.isSuccess() && realtimeUploadResponse.getReturnCode() == 0) {
                    binding.setCorpSerNo(realtimeUploadResponse.getMsgId());
                    SettlementAccountOpenResponseV2 settlementAccountOpenResponseV2 = icbcService.settlementAccountOpenV2(accountOpen, binding);
                    binding.setSmsSendNo(settlementAccountOpenResponseV2.getSmsSendNo());
                    accountOpenBindingDao.save(binding);
                    return successMessage(settlementAccountOpenResponseV2);
                } else {
                    accountOpenBindingDao.save(binding);
                    return errorMessage(MessageCode.code_444, realtimeUploadResponse.getReturnMsg());
                }
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }
    @ApiOperation("开户短信验证")
    @PostMapping("/accountOpenVerify")
    public String accountOpenVerify(@RequestBody AccountOpenVerifyParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<AccountOpenVerifyParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            AccountOpen accountOpen = accountOpenDao.findTop1ByUserOrderByIdDesc(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            final AccountOpenBinding binding = accountOpenBindingDao.findByOpenAndBindCard(accountOpen, params.getBindCard());
            if (null == binding) return errorMessage(MessageCode.code_444, "此卡未提交绑定操作");
            IcbcData icbcData = icbcDataDao.findByUserId(user.getId());
            final SettlementAccountSCodeVerifyResponseV1 response;
            try {
                response = icbcService.settlementAccountSCodeVerifyV1(binding, params.getSmsCode());
                if (response.isSuccess() && response.getReturnCode() == 0) {
                    //成功
                    final String mediumId = SecretUtils.decryptMediumId(response.getMediumId(), response.getSecretKey(), MY_SM2_PRIVATE_KEY);
                    System.out.println("II类卡号：" + mediumId);
                    accountOpen.setCard2(mediumId);
                    if (icbcData != null) {
                        icbcData.setCard(mediumId);
                        icbcDataDao.save(icbcData);
                    }
                    accountOpenDao.save(accountOpen);
                }
            } catch (IcbcApiException e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }

            return successMessage(response, new KeyValue("account", accountOpen));
        });
    }

    @ApiOperation("开户短信验证重发")
    @PostMapping("/accountOpenResend")
    public String accountOpenResend(@RequestBody BindCardParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<BindCardParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            AccountOpen accountOpen = accountOpenDao.findTop1ByUserOrderByIdDesc(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            final AccountOpenBinding binding = accountOpenBindingDao.findByOpenAndBindCard(accountOpen, params.getBindCard());
            if (null == binding) return errorMessage(MessageCode.code_444, "此卡未提交绑定操作");

            try {
                return successMessage(icbcService.settlementAccountSCodeSendV1(binding));
            } catch (IcbcApiException e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }

    @ApiOperation("查询缴纳的诚意金")
    @PostMapping("/sincer")
    public String sincer(@RequestBody SincerParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<SincerParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return successMessage(false);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return successMessage(false);

            if (!accountOpen.isSuccess()) {
                return successMessage(false);
            }

            double buildingHoldBalance = 0;
            if (params.getBuildingId() > 0) {
                buildingHoldBalance = NumberUtil.fen2Yuan(accountHoldDao.sumOfHoldBalance(user.getId()).longValue());
            }

            try {
                return successMessage(icbcService.settlementAccountBalanceQueryV1(accountOpen), new KeyValue("buildingHoldBalance", buildingHoldBalance));
            } catch (Exception e) {
                e.printStackTrace();
                //return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
                return successMessage(false);
            }
        });
    }

    @ApiOperation("交易流水")
    @PostMapping("/transactions")
    public String transactions(@RequestBody TransactionsParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TransactionsParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "未开户");

            if (!accountOpen.isSuccess()) {
                return errorMessage(MessageCode.code_444, "未开户");
            }

            try {
                return successMessage(icbcService.settlementAccountDetailQueryV1(accountOpen, params.getQueryMode(), params.getPage(), params.getPnBusidate(), params.getPnRowRecord()));
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }

    @ApiOperation("缴存诚意金")
    @PostMapping("/hold")
    public String hold(@RequestBody HoldParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<HoldParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");

            if (!accountOpen.isSuccess()) {
                return errorMessage(MessageCode.code_444, "二类账户还未开户成功");
            }

            final SettlementAccountHoldResponseV1 response;
            try {
                response = icbcService.settlementAccountHoldV1(accountOpen, params.getMoney(), params.getBuildingId());
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
            if (response.isSuccess() && response.getReturnCode() == 0) {
                // 业务成功处理
                System.out.println("实际余额：" + response.getAccountBalance());
                System.out.println("可用余额：" + response.getAccountUseamt());
                accountHoldDao.save(new AccountHold(user, params.getBuildingId(), params.getMoney(), Integer.valueOf(response.getAccountBalance()), Integer.valueOf(response.getAccountUseamt()), 0));
            }

            return successMessage(response);
        });
    }

    @ApiOperation("已缴存的诚意金列表")
    @PostMapping("/holds")
    public String holds(@RequestBody HoldsPagingParams params) {
        final Set<ConstraintViolation<HoldsPagingParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Specification<AccountHold> specification = (Specification<AccountHold>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getUserId() > 0) {
                predicates.add(criteriaBuilder.equal(root.get("user").get("id"), params.getUserId()));
            }
            if (params.getBuildingId() > 0) {
                predicates.add(criteriaBuilder.equal(root.get("buildingId"), params.getBuildingId()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        final Page<AccountHold> pages = accountHoldDao.findAll(specification, PageRequest.of(params.getPage(), params.getLimit(), new Sort(Sort.Direction.DESC, "id")));
        List<AccountHoldDto> dtos = new ArrayList<>();
        pages.map(hold -> dtos.add(new AccountHoldDto(hold, globalService)));

        return successMessage(dtos, new KeyValue("page", params.getPage()), new KeyValue("total", pages.getTotalElements()));
    }

    @ApiOperation("缴存诚意金解冻")
    @PostMapping("/unhold")
    public String unhold(@RequestBody IdTokenParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            final AccountHold accountHold = accountHoldDao.findById(params.getTargetId()).orElse(null);
            if (null == accountHold) return errorMessage(MessageCode.code_404, "未找到该缴存记录");
            if (accountHold.getUnholdTime() > 0) return errorMessage(MessageCode.code_444, "该缴存记录已解冻，无需重复解冻");

            final SettlementAccountUnholdResponseV1 response;
            try {
                response = icbcService.settlementAccountUnholdV1(accountOpen, accountHold);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
            if (response.isSuccess() && response.getReturnCode() == 0) {
                // 业务成功处理
                System.out.println("实际余额：" + response.getAccountBalance());
                System.out.println("可用余额：" + response.getAccountUseamt());
                accountHold.setUnholdTime(JodaUtils.getTimestamp());
                accountHoldDao.save(accountHold);
            }
            return successMessage(response);
        });
    }

    @ApiOperation("查询绑定的一类账户")
    @PostMapping("/bindings")
    public String bindings(@RequestBody IdTokenParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");

            final SettlementAccountBindingQueryResponseV1 response;
            try {
                response = icbcService.settlementAccountBindingQueryV1(accountOpen);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
            List<JSONObject> banks = new ArrayList<>();
            if (response.isSuccess()) {
                for (String detail : response.getRecordDetail()) {
                    final JSONObject object = JSON.parseObject(detail);
                    final String bindMedium = object.getString("bind_medium");
                    final String bankTp = object.getString("bank_tp");
                    final String mediumId = SecretUtils.decryptMediumId(bindMedium, response.getSecretKey(), MY_SM2_PRIVATE_KEY);
                    System.out.println("绑定卡号：" + mediumId);
                    final JSONObject bank = new JSONObject();
                    bank.put("mediumId", mediumId);
                    bank.put("bankTp", bankTp);
                    banks.add(bank);
                }
            }
            return successMessage(response, new KeyValue("banks", banks));
        });
    }

    @ApiOperation("绑定一类账户")
    @PostMapping("/binding")
    public String binding(@RequestBody BindingParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<BindingParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            if (!accountOpen.isSuccess()) {
                return errorMessage(MessageCode.code_444, "二类账户还未开户成功");
            }
            AccountOpenBinding binding = accountOpenBindingDao.findByOpenAndBindCard(accountOpen, params.getBindCard());
            if (null != binding) return errorMessage(MessageCode.code_444, "此卡已提交绑定操作，若无法使用，请解绑后重新绑定");

            binding = new AccountOpenBinding();
            binding.setOpen(accountOpen);
            binding.setMobile(params.getMobile());
            binding.setBindCard(params.getBindCard());
            binding.setType(1);
            accountOpenBindingDao.save(binding);

            try {
                final SettlementAccountBindingResponseV1 response = icbcService.settlementAccountBindingV1(accountOpen, binding);
                return successMessage(response);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }

    @ApiOperation("取消一类账户的绑定")
    @PostMapping("/unbinding")
    public String unbinding(@RequestBody BindCardParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<BindCardParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            AccountOpenBinding binding = accountOpenBindingDao.findByOpenAndBindCard(accountOpen, params.getBindCard());
            if (null == binding) return errorMessage(MessageCode.code_444, "此卡未提交绑定操作");

            final SettlementAccountUnbindingResponseV1 response;
            try {
                response = icbcService.settlementAccountUnbindingV1(accountOpen, binding);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
            if (response.isSuccess()) {
                accountOpenBindingDao.delete(binding);
            }
            return successMessage(response);
        });
    }

    /*@ApiOperation("账户资金互转")
    @PostMapping("/transfer")
    public String transfer(@RequestBody TransferParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TransferParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            if (!accountOpen.isSuccess()) {
                return errorMessage(MessageCode.code_444, "二类账户还未开户成功");
            }

            try {
                final SettlementAccountOrientedTransferResponseV1 response = icbcService.settlementAccountOrientedTransferV1(accountOpen, params.getOutBankNumber(), params.getInBankNumber(), params.getMoney());
                return successMessage(response);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }*/

    @ApiOperation("充值")
    @PostMapping("/recharge")
    public String recharge(@RequestBody TransferParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TransferParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            if (!accountOpen.isSuccess()) {
                return errorMessage(MessageCode.code_444, "二类账户还未开户成功");
            }

            try {
                final SettlementAccountRechargeResponseV1 response = icbcService.settlementAccountRechargeV1(accountOpen, params.getAccountNumber1(), params.getMoney());
                return successMessage(response);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }

    @ApiOperation("提现")
    @PostMapping("/withdraw")
    public String withdraw(@RequestBody TransferParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TransferParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        return (String) redisSyncLocker.idLock(params.resolveUserId(), o -> {
            final User user = userDao.findById(params.resolveUserId()).orElse(null);
            if (null == user) return errorMessage(MessageCode.code_777);
            final AccountOpen accountOpen = accountOpenDao.findTop1ByUser(user);
            if (null == accountOpen) return errorMessage(MessageCode.code_444, "您还未提交开户信息，请先提交开户");
            if (!accountOpen.isSuccess()) {
                return errorMessage(MessageCode.code_444, "二类账户还未开户成功");
            }

            try {
                final SettlementAccountWithdrawResponseV1 response = icbcService.settlementAccountWithdrawV1(accountOpen, params.getAccountNumber1(), params.getMoney());
                return successMessage(response);
            } catch (Exception e) {
                e.printStackTrace();
                return errorMessage(MessageCode.code_444, "银行通道不可用，请稍候再试，错误信息：" + e.getMessage());
            }
        });
    }

    @ApiOperation("开户回调")
    @PostMapping("/openNotify")
    public String openNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String stream = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        System.out.println(stream);
        System.out.println(JSON.toJSONString(request.getParameterMap()));
        return successMessage();
    }

    @ApiOperation("绑定回调")
    @PostMapping("/bindingNotify")
    public String bindingNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String stream = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        System.out.println(stream);
        System.out.println(JSON.toJSONString(request.getParameterMap()));
        return successMessage();
    }

    @ApiOperation("充值回调")
    @PostMapping("/rechargeNotify")
    public String rechargeNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String stream = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        System.out.println(stream);
        System.out.println(JSON.toJSONString(request.getParameterMap()));
        return successMessage();
    }

    @ApiOperation("提现回调")
    @PostMapping("/withdrawNotify")
    public String withdrawNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String stream = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        System.out.println(stream);
        System.out.println(JSON.toJSONString(request.getParameterMap()));
        return successMessage();
    }
}
